.model small

;
; imports
;
extrn printc : near		;, draw : near
extrn draw : near
extrn data1
extrn data2
extrn semaphores 

south equ 0
east equ 3
north equ 6
west equ 9
left equ 0
forward equ 1
right equ 2
off equ 0
red equ 1
yellow equ 2
green equ 3


;
; description:	macro for getting the argument passed through the stack
; parameters:	x	-	the order number from the top of the stack
;				reg	-	the register for saving the argument
;
getArg macro reg, x
mov reg, [bp + 4 + 2*x]
endm

;
; description:	macro for passing the return value on the stack
; parameter:	x	-	the order number from the top of the stack
;				reg	-	the register that holds the returning value
;
setArg macro reg, x
mov [bp + 4 + 2*x], reg
endm

.data 
	data1main db ?
	data2main db ?
	
	timeInitial dw 17000, 17000, 17000, 17000, 17000, 17000, 17000 ;for debug only!!! FIX: 7 dup (?)
	timeGainMax dw 7000, 7000, 0, 7000, 7000, 0;
	timeGain dw 6 dup (0);
	timeCurrent dw 700	;for debug, FIX: ?
	currentTimer db 0	;for debug, FIX:  (?) ; one of bellow
	VLR equ 0	; vertical left right
	VFR equ 2	; vertical forward right
	VF	equ 4	; vertical forward
	HLR equ 6	; vertical left right
	HFR equ 8	; vertical forward right
	HF	equ 10	; vertical forward
	YYY equ 12	; all yellow
	redTime equ 1000; // ms
	yellowTime equ 1000
	
	arriveedFlag dw 0, 0
	crossingFlag dw 0, 0
	crossingTimeLeft dw 0, 0
	crossingLightColor dw off, off
	crossingDisplayColor dw off, off
	Horizontal equ 2
	Vertical equ 0
	timeTick equ 55
	
.stack 100h

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; code segment
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.code

pedUpdate macro direction
	lea bx, crossingTimeLeft
	mov [bx][direction], ax
	mov ax, direction
	push ax
	push ax
	call calcPedLight
	pop ax
	lea bx, crossingLightColor
	mov [bx][direction], ax
	call calcPedDispLight
	pop ax
	mov bx, crossingDisplayColor
	mov [bx][direction], ax
endm
;--------------------------------------------------
;	reg<>bx
verticalStatesTime macro reg
push bx
lea bx, timeInitial
mov reg, [bx][VLR]
add reg, [bx][VRF]
add reg, [bx][VF]
pop bx
endm
;--------------------------------------------------
;--------------------------------------------------
;	reg<>bx
horizontalStatesTime macro reg
push bx
lea bx, timeInitial
mov reg, [bx][HLR]
add reg, [bx][HRF]
add reg, [bx][HF]
pop bx
endm
;--------------------------------------------------

;--------------------------------------------------
;	calculates the light
;	Light calculateLight(void)
;	example of usage:
;		sub sp, 2
;		call calculateLight
;		pop ax
calculateLight proc near
	push bp
	mov bp, sp

	push ax
	push dx
	
	mov ax, timeCurrent
	sub ax, redTime
	cmp ax, 0
	jle calcTime_red
	cmp ax, yellowTime
	jle calcTime_yellow
	cmp ax, yellowTime + 500
	jle	calcTime_green
	cmp ax, yellowTime +  1000
	jle	calcTime_off
	cmp ax, yellowTime +  1500
	jle	calcTime_green
	cmp ax, yellowTime +  2000
	jle	calcTime_off
	cmp ax, yellowTime +  2500
	jle	calcTime_green
	cmp ax, yellowTime +  3000
	jle	calcTime_off
	
	sub sp, 2
	call initialTime
	pop dx
	sub dx, redTime
	cmp ax, dx
	jge calcTime_red
	sub dx, yellowTime
	cmp ax, dx
	jge calcTime_yellow
calcTime_green:
	mov dx, green
	jmp calcTime_light
calcTime_yellow:
	mov dx, yellow
	jmp calcTime_light
calcTime_off:
	mov dx, off
	jmp calcTime_light
calcTime_red:
	mov dx, red
	
calcTime_light:
	setArg dx, 0
	
	pop dx
	pop ax
	pop bp
	ret
calculateLight endp
;--------------------------------------------------

;
;	push horizontal/vertical
;	call calcPedLight
;	pop reg	
;
calcPedLight proc
	push bp
	mov bp, sp

	push ax
	push bx
	push di
	
	lea bx, crossingFlag
	getArg di 0
	mov ax, [bx][di]
	cmp ax, 1
	jne calcPL_cross
	mov ax, red
	jmp calcPL_end
calcPL_cross:
	lea bx, crossingTimeLeft
	mov ax, [bx][di]
	cmp ax, 10000
	jl calcPL_blink
	mov ax, green
	jl calcPL_end
calcPL_blink:
	mov bx, 700d
	div bx
	and ax, 01h
	cmp ax, 0
	je calcPL_even
	mov ax, off
	jmp calcPL_end
calcPL_even:
	mov ax, green
calcPL_end:
	setArg ax 0
	
	pop di
	pop bx
	pop ax
	
	pop bp
	ret
calcPedLight endp

;
;	push horizontal/vertical
;	call calcPedLight
;	pop reg
;
calcPedDispLight proc
	push bp
	mov bp, sp

	push ax
	push bx
	push di
	
	lea bx, crossingFlag
	getArg di 0
	mov ax, [bx][di]
	cmp ax, 1
	jne calcPDL_cross
	mov ax, red
	jmp calcPDL_end
calcPDL_cross:
	lea bx, crossingTimeLeft
	mov ax, [bx][di]
	cmp ax, 10000
	jl calcPDL_yellow
	mov ax, green
	jl calcPDL_end
calcPDL_yellow:
	mov ax, yellow
calcPDL_end:
	setArg ax 0
	
	pop di
	pop bx
	pop ax
	
	pop bp
	ret
calcPedDispLight endp

;--------------------------------------------------
;
;	push arg
;	call restartTimer
;
;--------------------------------------------------
restartTimer proc near
	push bp
	mov bp, sp
	push ax
	push bx
	push di
	push dx
	
	getArg ax 0
	mov di, ax
	lea bx, timeInitial
	mov dx, [bx][di]
	
	push ax
	call timeGained
	pop ax
	
	add ax, dx
	
	pop dx
	pop di
	pop bx
	pop ax
	pop bp
	ret 2
restartTimer endp

;--------------------------------------------------
;   returns time that iteraton length differs 
;           from the initial one
;	signature: long timeGained( direction )
;						direction: VLR||VFR||...||HF
;
;	push arg
;	call timeGained
;	pop reg
;
;--------------------------------------------------
timeGained proc near
	push bp
	mov bp, sp
	push ax
	push bx
	push di
	
	getArg ax 0
	mov di, ax
	lea bx, timeGain
	
	cmp ax, VF
	jne timeGained_HF
	mov ax, [bx][VLR]
	add ax, [bx][VFR]
	jmp timeGainedRet
timeGained_HF:
	cmp ax, HF
	jne timeGained_else
	mov ax, [bx][HLR]
	add ax, [bx][HFR]
	jmp timeGainedRet
timeGained_else:
	mov ax, [bx][di]
	xor bx, bx
	sub bx, ax
	mov ax, bx
timeGainedRet:	
	setArg ax 0
	pop bx
	pop ax
	pop bp
	ret
timeGained endp

;----------------------------------------------
;	call:
;	sub sp, 2
;	call nextTimer
;	pop ax
;	
nextTimer proc
	push bp
	mov bp, sp
	
	push ax
	push bx
	xor ax, ax
	mov al, byte ptr currentTimer
	add ax, 2
	mov bl, 12
	div bl
	xor bx, bx
	mov bl, ah
	
	setArg bx, 0
	
	pop bx
	pop ax
	pop bp ; next timer
nextTimer endp
;----------------------------------------------

;------------------------------------------------
;	long initialTime(void)
;
;	calling (ax <- initialTime):
;	sub sp, 2
;	call initialTime
;	pop ax
;------------------------------------------------
initialTime proc
	push bp
	mov bp, sp
	
	push ax
	push bx
	push dx
	push di
	
	xor ax, ax
	mov al, currentTimer
	push ax
	call timeGained
	pop dx
	
	lea bx, timeInitial
	mov di, ax
	mov ax, [bx][di]
	sub ax, dx
	
	setArg ax, 0
	pop di
	pop dx
	pop bx
	pop ax
	
	pop bp
	ret
initialTime endp

tickVLR proc
	mov di, south + right
	mov ax, green
	mov byte ptr[bx][di], al
	mov di, north + right
	mov byte ptr[bx][di], al
	mov ax, left
	mov di, south
	add di, ax
	mov byte ptr[bx][di], dl
	mov di, north
	add di, ax
	mov byte ptr[bx][di], dl
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][VFR]
	lea bx, arriveedFlag
	mov cx, [bx][Horizontal]
	cmp cx, 0
	je tick_VLR_H_n_arr
	lea bx, timeGainMax
	mov cx, [bx][VFR]
	sub ax, cx
tick_VLR_H_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Horizontal], 0
	lea bx, crossingTimeLeft
	mov [bx][Horizontal], ax
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][VFR]
	add ax, [bx][VF]
	add ax, [bx][HLR]
	add ax, [bx][HFR]
	mov cx, VLR
	push cx
	call timeGained
	pop cx
	sub ax, cx
	lea bx, arriveedFlag
	mov cx, [bx][Vertical]
	cmp cx, 0
	je tick_VLR_V_n_arr
	lea bx, timeGainMax
	mov cx, [bx][HLR]
	sub ax, cx
	mov cx, [bx][HFR]
	sub ax, cx
tick_VLR_V_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Vertical], 0
	lea bx, crossingTimeLeft
	mov [bx][Vertical], ax
	
	ret
tickVLR endp

tickHLR proc

	mov di, west + right
	mov ax, green
	mov byte ptr[bx][di], al
	mov di, east + right
	mov byte ptr[bx][di], al
	mov ax, left
	mov di, west
	add di, ax
	mov byte ptr[bx][di], dl
	mov di, east
	add di, ax
	mov byte ptr[bx][di], dl
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][HFR]
	lea bx, arriveedFlag
	mov cx, [bx][Vertical]
	cmp cx, 0
	je tick_HLR_V_n_arr
	lea bx, timeGainMax
	mov cx, [bx][HFR]
	sub ax, cx
tick_HLR_V_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Vertical], 0
	lea bx, crossingTimeLeft
	mov [bx][Vertical], ax
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][HFR]
	add ax, [bx][HF]
	add ax, [bx][VLR]
	add ax, [bx][VFR]
	mov cx, HLR
	push cx
	call timeGained
	pop cx
	sub ax, cx
	lea bx, arriveedFlag
	mov cx, [bx][Horizontal]
	cmp cx, 0
	je tick_HLR_H_n_arr
	lea bx, timeGainMax
	mov cx, [bx][VLR]
	sub ax, cx
	mov cx, [bx][VFR]
	sub ax, cx
tick_HLR_H_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Horizontal], 0
	lea bx, crossingTimeLeft
	mov [bx][Horizontal], ax
	
	ret
tickHLR endp

tickVFR proc
	mov di, south + forward
	mov ax, green
	mov byte ptr[bx][di], al
	mov di, north + forward
	mov byte ptr[bx][di], al
	mov ax, right
	mov di, south
	add di, ax
	mov byte ptr[bx][di], dl
	mov di, north
	add di, ax
	mov byte ptr[bx][di], dl
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	
	lea bx, crossingFlag
	mov word ptr [bx + Horizontal], 0
	lea bx, crossingTimeLeft
	mov [bx][Horizontal], ax
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][VF]
	add ax, [bx][HLR]
	add ax, [bx][HFR]
	mov cx, VFR
	push cx
	call timeGained
	pop cx
	add ax, cx
	mov cx, VLR
	push cx
	call timeGained
	pop cx
	add ax, cx
	lea bx, arriveedFlag
	mov cx, [bx][Vertical]
	cmp cx, 0
	je tick_VFR_V_n_arr
	lea bx, timeGainMax
	mov cx, [bx][HLR]
	sub ax, cx
	mov cx, [bx][HFR]
	sub ax, cx
tick_VFR_V_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Vertical], 0
	lea bx, crossingTimeLeft
	mov [bx][Vertical], ax
	
	ret
tickVFR endp

tickHFR proc

	mov di, west + forward
	mov ax, green
	mov byte ptr[bx][di], al
	mov di, east + forward
	mov byte ptr[bx][di], al
	mov ax, right
	mov di, west
	add di, ax
	mov byte ptr[bx][di], dl
	mov di, east
	add di, ax
	mov byte ptr[bx][di], dl
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	lea bx, crossingFlag
	mov word ptr [bx + Vertical], 0
	lea bx, crossingTimeLeft
	mov [bx][Vertical], ax
	
	mov ax, timeCurrent
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][HF]
	add ax, [bx][VLR]
	add ax, [bx][VFR]
	mov cx, HFR; sub? i think its sub
	push cx
	call timeGained
	pop cx
	add ax, cx
	mov cx, HLR
	push cx
	call timeGained
	pop cx
	add ax, cx
	lea bx, arriveedFlag
	mov cx, [bx][Horizontal]
	cmp cx, 0
	je tick_HFR_H_n_arr
	lea bx, timeGainMax
	mov cx, [bx][VLR]
	sub ax, cx
	mov cx, [bx][VFR]
	sub ax, cx
tick_HFR_H_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Horizontal], 0
	lea bx, crossingTimeLeft
	mov [bx][Horizontal], ax
	
	ret
tickHFR endp

tickVF proc	
	
	mov ax, forward
	mov di, south
	add di, ax
	mov byte ptr[bx][di], dl
	mov di, north
	add di, ax
	mov byte ptr[bx][di], dl
	
	mov ax, timeCurrent
	sub sp, 2
	call initialTime
	pop cx
	sub cx, redTime
	cmp ax, cx
	jl tickVF_green
	sub ax, cx
	lea bx, crossingFlag
	mov word ptr [bx + Horizontal], 0
	lea bx, crossingTimeLeft
	mov [bx][Horizontal], ax
	jmp tickVF_V
tickVF_green:
	lea bx, crossingFlag
	mov word ptr[bx + Horizontal], 1
	lea bx, crossingTimeLeft
	mov [bx][Horizontal], ax

tickVF_V:
	mov ax, timeCurrent	
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][HLR]
	add ax, [bx][HFR]
	lea bx, arriveedFlag
	mov cx, [bx][Vertical]
	cmp cx, 0
	je tick_VF_V_n_arr
	lea bx, timeGainMax
	mov cx, [bx][HLR]
	sub ax, cx
	mov cx, [bx][HFR]
	sub ax, cx
tick_VF_V_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Vertical], 0
	lea bx, crossingTimeLeft
	mov [bx][Vertical], ax
		
	ret
tickVF endp

tickHF proc	
	
	mov ax, forward
	mov di, west
	add di, ax
	mov byte ptr[bx][di], dl
	mov di, east
	add di, ax
	mov byte ptr[bx][di], dl
	
	mov ax, timeCurrent
	sub sp, 2
	call initialTime
	pop cx
	sub cx, redTime
	cmp ax, cx
	jl tickHF_green
	sub ax, cx
	lea bx, crossingFlag
	mov word ptr [bx + Vertical], 0
	lea bx, crossingTimeLeft
	mov [bx][Vertical], ax
	jmp tickHF_H
tickHF_green:
	lea bx, crossingFlag
	mov word ptr[bx + Vertical], 1
	lea bx, crossingTimeLeft
	mov [bx][Vertical], ax

tickHF_H:
	mov ax, timeCurrent	
	lea bx, timeInitial
	add ax, redTime
	add ax, [bx][VLR]
	add ax, [bx][VFR]
	lea bx, arriveedFlag
	mov cx, [bx][Horizontal]
	cmp cx, 0
	je tick_HF_H_n_arr
	lea bx, timeGainMax
	mov cx, [bx][VLR]
	sub ax, cx
	mov cx, [bx][VFR]
	sub ax, cx
tick_HF_H_n_arr:
	lea bx, crossingFlag
	mov word ptr [bx + Horizontal], 0
	lea bx, crossingTimeLeft
	mov [bx][Horizontal], ax
	
	ret
tickHF endp

;------------------------------------------------
;	void tick(void)
;------------------------------------------------
tick proc near
	push bp
	mov bp, sp
	sub sp, 6 ;next timer(if needed) 
	push ax
	
	; determines the light
	sub sp, 2
	call calculateLight
	pop dx
	; set light
tick_light:
	lea bx, semaphores
	xor ax, ax
	mov al, byte ptr currentTimer
	cmp ax, VLR
	je tick_VLR
	cmp ax, VFR
	je tick_VFR
	cmp ax, VF
	je tick_VF
	cmp ax, HLR
	je tick_HLR
	cmp ax, HFR
	je tick_HFR
	cmp ax, HF
	je tick_HF
	; YYY	TODO!

tick_VLR:
	call tickVLR
	jmp tick_update
tick_VFR:
	call tickVFR
	jmp tick_update
tick_VF:	
	call tickVF
	jmp tick_update
tick_HLR:
	call tickHLR
	jmp tick_update
tick_HFR:
	call tickHFR
	jmp tick_update
tick_HF:	
	call tickHF
	jmp tick_update
tick_update:
	
;set colors for display and pedestrian semaphore

	mov ax, Vertical
	push ax
	push ax
	call calcPedLight
	pop ax
	lea bx, crossingLightColor
	mov [bx][Vertical], ax
	call calcPedDispLight
	pop ax
	lea bx, crossingDisplayColor
	mov [bx][Vertical], ax
	
	; TODO: update colors and numbers in UI!
	
	mov ax, Horizontal
	push ax
	push ax
	call calcPedLight
	pop ax
	lea bx, crossingLightColor
	mov [bx][Horizontal], ax
	call calcPedDispLight
	pop ax
	lea bx, crossingDisplayColor
	mov [bx][Horizontal], ax

	; TODO: update colors and numbers in UI!
	
; update state
	
	mov ax, timeCurrent
	sub ax, timeTick
	cmp ax, 0
	jg tick_end
	;	get next timer
	xor dx, dx
	mov dl, currentTimer
	cmp dx, VF
	je tick_VF_reset
	cmp dx, HF
	je tick_HF_reset
	jmp tick_next_state
tick_VF_reset:
	lea bx, arriveedFlag
	mov word ptr [bx + Horizontal], 0
	jmp tick_next_state
tick_HF_reset:
	lea bx, arriveedFlag
	mov word ptr [bx + Vertical], 0
tick_next_state:
	sub sp, 2
	call nextTimer
	pop ax
	mov di, ax
	mov currentTimer, al
	lea bx, timeInitial
	mov ax, [bx][di]
	
tick_end:
	mov timeCurrent, ax
	pop ax
	
	add sp, 6
	pop bp
	ret
tick endp

;----------------------------------------------------
; signature:	Light getSemLight( Semaphore *, Side, Order)
;				>	Semaphore	-	address of the beggining of the semaphore
;				>	Side		-	south, east, north, west (0, 1, 2, 3)
;				>	Order		-	left, foreward, right (0, 1, 2)
; description:	gets the semaphore light
; comment:		the arguments and the return value are passed through the stack;
;				frees the arguments on the stack
; returns:		The light of the semaphore through the stack
getSemLight proc near
	push bp
	mov bp, sp
	
	push ax
	push bx
	push di

	;mov bx, ldArg 0
	getArg bx 0
	getArg di 1
	getArg ax 2
	add di, ax
	mov al, byte ptr[bx+di]
	setArg ax 2
	
	pop di
	pop bx
	pop ax
	pop bp
	ret 4
getSemLight endp
;----------------------------------------------------

;----------------------------------------------------
; signature:	void setSemLight( Semaphore *, Side, Order, Light)
;				>	Semaphore	-	address of the beggining of the semaphore
;				>	Side		-	south, east, north, west (0, 1, 2, 3)
;				>	Order		-	left, foreward, right (0, 1, 2)
;				>	Light		-	light to set
; description:	sets the semaphore light
; comment:		the arguments are passed through the stack;
;				frees the arguments on the stack
setSemLight proc near
	push bp
	mov bp, sp
	
	push ax
	push bx
	push di

	getArg bx 0
	getArg di 1
	getArg ax 2
	add di, ax
	getArg ax 3
	mov byte ptr[bx+di], al
	
	pop di
	pop bx
	pop ax
	pop bp
	ret 8
setSemLight endp
;----------------------------------------------------

;-------------------------------------------
; signature - void initSems(byte* sems)
; description - initializes semaphores
; stack - sems
;-------------------------------------------
initSems proc near
	push bp
	mov bp, sp
	; save locals
	push ax
	push bx
	push cx
	push di
	
	mov al, red
	mov bx, [bp+4]
	mov di, 0
	mov cx, 12
	initSemsLoop:
		mov byte ptr[bx+di], al
		inc di
		loop initSemsLoop
	
	; restore locals
	pop di
	pop cx
	pop bx
	pop ax
	; return
	pop bp
	ret
initSems endp


;////////////////////////////////////////////////////////////
;	main program
;////////////////////////////////////////////////////////////
main proc

	; initialize ds
	mov ax, @DATA
	mov ds, ax

	; initialize semapfores
	lea ax, semaphores
	push ax
	call initSems
	pop ax
	
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	call tick
	
	;
	;setSemLightMacro semaphores east right yellow
	mov ax, yellow
	push ax
	mov ax, right
	push ax
	mov ax, east
	push ax
	lea ax, semaphores
	push ax
	call setSemLight
	
	;	set data1
	mov ax, 67
	inc ax
	mov byte ptr data1, al

	;
	;getSemLightMacro semaphores east right
	
	mov ax, right
	push ax
	mov ax, east
	push ax
	lea ax, semaphores
	push ax
	call getSemLight
	pop ax
	
	;	set data2
	inc ax
	inc ax
	mov byte ptr data2, al

	call draw
	
	;	return to dos
	mov ah, 4ch
	int 21h

main endp
;////////////////////////////////////////////////////////////

end main	;MAIN - entry point
